package com.vinxin.app.service

import cn.hutool.core.bean.BeanUtil
import cn.hutool.core.util.StrUtil
import cn.hutool.log.Log
import cn.hutool.log.LogFactory
import com.alibaba.fastjson2.JSONArray
import com.alibaba.fastjson2.JSONPath
import com.vinxin.app.boss.feign.BossFeign
import com.vinxin.app.boss.model.FiltersRequest
import com.vinxin.app.boss.model.JobhunterListRequest
import com.vinxin.app.boss.model.TriggerChatRequest
import com.vinxin.app.boss.model.TriggerChatUsedRequest
import com.vinxin.app.exception.ResponseCodeEnum
import com.vinxin.app.exception.VXException
import com.vinxin.app.model.*
import com.vinxin.app.utils.JacksonUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.Resource
import org.springframework.http.HttpHeaders
import org.springframework.stereotype.Service
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.util.*


@Service
class JobhunterService {
    private val log: Log = LogFactory.get()

    @Value("classpath:temp.json")
    private val resource: Resource? = null

    @Autowired
    private lateinit var bossFeign: BossFeign

    @Throws(IOException::class)
    fun readExampleFile(): String {
        val contentBuilder = StringBuilder()
        resource?.inputStream?.let { InputStreamReader(it, StandardCharsets.UTF_8) }?.let { it ->
            BufferedReader(it).use { reader ->
                var line: String?
                while ((reader.readLine().also { line = it }) != null) {
                    contentBuilder.append(line).append(System.lineSeparator())
                }
            }
        }
        return contentBuilder.toString()
    }

    fun getList(payload: JobhunterListPayload, headers: HttpHeaders): List<JobhunterVo> {
        val jobhunterVoList = payload.salaries.stream().flatMap {
            Thread.sleep(1000)
            val response = getJobhunterList(
                bossFeign.getJobhunterList(
                    headers,
                    BeanUtil.beanToMap(JacksonUtils.toObj(payload.copy(salary = it), JobhunterListRequest::class.java))
                )
            )
            payload.page++
            return@flatMap response.stream()
        }.toList()
        jobhunterVoList.forEach { it.profileString = JacksonUtils.toJson(it) }

        val keywords = payload.keywords
        matchKeywords(keywords, jobhunterVoList)
        jobhunterVoList.forEach { it.pageNumber = payload.page }
        val result = jobhunterVoList
            .takeIf { keywords.isEmpty() }
            ?: jobhunterVoList.filter { it.matchCount > 0 }.sortedBy { it.matchCount }.reversed()
        return result.ifEmpty {
            getList(payload, headers)
        }
    }

    private fun matchKeywords(keywords: Set<String>, jobhunterVoList: List<JobhunterVo>) {
        keywords.forEach { keyword ->
            jobhunterVoList.forEach {
                it.matchCount += countOccurrences(it.profileString, keyword)
            }
        }
    }

    private fun countOccurrences(content: String, searchString: String): Int {
        val lowerContent = content.lowercase(Locale.getDefault())
        val lowerSearchString = searchString.lowercase(Locale.getDefault())
        var count = 0
        var index = 0
        while (index != -1) {
            index = lowerContent.indexOf(lowerSearchString, index)
            if (index != -1) {
                count++
                index += lowerSearchString.length
            }
        }
        return count
    }

    private fun getJobhunterList(result: String): List<JobhunterVo> {
        val size: Int = JSONPath.extract(result, "$.geekList.size()")?.toString()?.toIntOrNull() ?: 0
        return (0 until size).mapIndexed { index, _ ->
            JobhunterVo(
                JSONPath.extract(result, "$.geekList[$index].encryptGeekId")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.geekName")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].activeTimeDesc")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.expectId")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.securityId")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.lid")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].suid")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.ageDesc")?.toString() ?: "",
                (JSONPath.extract(result, "$.geekList[$index].geekCard.geekGender")?.toString() ?: "1").toInt(),
                JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorkYear")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.geekDegree")?.toString() ?: "",
                JSONPath.extract(result, "$.geekList[$index].geekCard.applyStatusDesc")?.toString() ?: "",
                ExpectJobVo(
                    JSONPath.extract(result, "$.geekList[$index].geekCard.expectLocationName")?.toString() ?: "",
                    JSONPath.extract(result, "$.geekList[$index].geekCard.expectPositionName")?.toString() ?: "",
                    JSONPath.extract(result, "$.geekList[$index].geekCard.salary")?.toString() ?: ""
                ),
                DegreeSchoolVo(
                    JSONPath.extract(result, "$.geekList[$index].geekCard.geekEdu.startDate")?.toString() ?: "",
                    JSONPath.extract(result, "$.geekList[$index].geekCard.geekEdu.endDate")?.toString() ?: "",
                    JSONPath.extract(result, "$.geekList[$index].geekCard.geekEdu.school")?.toString() ?: "",
                    JSONPath.extract(result, "$.geekList[$index].geekCard.geekEdu.major")?.toString() ?: ""
                ),
                (0 until JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks.size()") as Int).mapIndexed { workIndex, _ ->
                    WorkExperienceVo(
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].company")?.toString() ?: "",
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].positionName")?.toString() ?: "",
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].startDate")?.toString() ?: "",
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].endDate")?.toString() ?: "",
                        null,
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].workTime")?.toString() ?: "",
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].responsibility")?.toString() ?: "",
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].workPerformance")?.toString() ?: "",
                        JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].workEmphasis")?.toString() ?: "",
                        (JSONPath.extract(result, "$.geekList[$index].geekCard.geekWorks[$workIndex].workEmphasisList") as JSONArray?)?.stream()
                            ?.map { it.toString() }?.toList()?.toSet() ?: setOf()
                    )
                }.toList(),
                JSONPath.extract(result, "$.geekList[$index].geekCard.geekDesc.content")?.toString() ?: "",
                extractWorkSkillLabelSet(result, index),
                emptyList(),
                0,
                "",
                0
            )
        }.toList()
    }

    private fun extractWorkSkillLabelSet(jsonStr: String, index: Int): Set<String> {
        return (0 until JSONPath.extract(jsonStr, "$.geekList[$index].geekCard.geekWorks.size()") as Int).mapIndexed { workIndex, _ ->
            (JSONPath.extract(jsonStr, "$.geekList[$index].geekCard.geekWorks[$workIndex].workEmphasisList") as JSONArray?)?.stream()
                ?.map { it.toString().removeSuffix(".js").lowercase() }?.toList()?.toSet() ?: setOf()
        }.flatten().toSet()
    }

    fun triggerChat(payload: TriggerChatPayload, headers: HttpHeaders): String {
        val result = bossFeign.triggerChat(
            headers,
            JacksonUtils.toObj(payload, TriggerChatRequest::class.java)
        )
        val stateDesc = JSONPath.extract(result, "$.stateDesc")?.toString()
        return if (StrUtil.isBlank(stateDesc)) "SUCCESS" else throw VXException(ResponseCodeEnum.BAD_REQUEST, stateDesc)
    }

    fun getTriggerChatUsed(headers: HttpHeaders): String? {
        val result = bossFeign.getTriggerChatUsed(headers, BeanUtil.beanToMap(TriggerChatUsedRequest()))

        return JSONPath.extract(result, "$.headTitle")?.toString()
    }

    fun getFilterKeyword1(headers: HttpHeaders, jobId: String): List<SelectorVo> {
        val result = bossFeign.getFilters(headers, BeanUtil.beanToMap(FiltersRequest(jobId)))
        val size: Int = JSONPath.extract(result, "$.vipFilter.filters.size()")?.toString()?.toIntOrNull() ?: 0
//        return (0 until size).mapIndexed { index, _ ->
//            val jobName = JSONPath.extract(result, "$.onlineJobList[$index].jobName") as String
//            val locationName = JSONPath.extract(result, "$.onlineJobList[$index].locationName") as String
//            val salaryDesc = JSONPath.extract(result, "$.onlineJobList[$index].salaryDesc") as String
//            val encryptId = JSONPath.extract(result, "$.onlineJobList[$index].encryptId") as String
//
//            SelectorVo("$jobName $locationName $salaryDesc".replace(" ", "_"), encryptId)
//        }
        return emptyList()
    }
}